package arbitrage;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Scanner;
import java.util.regex.Pattern;

public class AsmReader {
	
	private HashMap<String,Integer> etiquettes;
	private MotMemoire[] prog;
	
	final static Pattern ETI = Pattern.compile("(\\p{Alnum}+)");
	final static Pattern INST = Pattern.compile("(MOV|ADD|SUB|JMP|JMZ|JMN|CMP|SLT|DJN|SPL|DAT)");
	final static Pattern MODE = Pattern.compile("(#|@|<)");
	final static Pattern VAL = Pattern.compile("(\\d+|-\\d+|" + ETI.pattern() + ")");
	final static Pattern OP = Pattern.compile("(" + MODE.pattern() + "?\\s*" + VAL.pattern() + ")");
	final static Pattern COM = Pattern.compile("(;.*)");
	final static Pattern OPER1 = Pattern.compile("((" + ETI.pattern() + "\\s+)?" + INST.pattern() + "\\s+" + OP.pattern() + ",?\\s+" + OP.pattern() + "(\\s+" + COM.pattern() + ")?)");
	final static Pattern OPER2 = Pattern.compile("((" + ETI.pattern() + "\\s+)?" + INST.pattern() + "\\s+" + OP.pattern() + "(\\s+" + COM.pattern() + ")?)");
	final static Pattern OPER = Pattern.compile("(" + OPER1.pattern() + "|" + OPER2.pattern() + ")");
	final static Pattern LIGNE = Pattern.compile("(" + COM.pattern() + "|" + OPER.pattern() + ")");
	
	public AsmReader() {
		etiquettes = new HashMap<String, Integer>();
		prog = new MotMemoire[VirtualMachine.MAXPROGLENGTH];
	}
	
   // Lire pour la 1ère fois le fichier .asm et récupérer la position relative des étiquettes
	private void setLabel(File fichier) throws FileNotFoundException, ProgramLengthException {
		Scanner sc = new Scanner(fichier);
    	int positionRelative = 0;
    	while (sc.hasNext() && (positionRelative <= VirtualMachine.MAXPROGLENGTH)) {
    		String firstString = sc.next();
			if (Pattern.matches(COM.pattern(), firstString)) {}
			else if (!Pattern.matches(INST.pattern(), firstString)) {
				etiquettes.put(firstString, positionRelative);
				positionRelative++;
			}
			else {positionRelative++;}
			sc.nextLine();
    	}
    	if (positionRelative > VirtualMachine.MAXPROGLENGTH) {throw new ProgramLengthException();}
    	sc.close();
    }
	
   // Traduire les lignes de codes et notamment transformer les étiquettes en chiffres
	private void setProgram(File fichier) throws FileNotFoundException, InstructionException, ModeException {
		Scanner sc = new Scanner(fichier);
		int positionRelative = 0;
    	while (sc.hasNext()) {
    		String ligne = sc.findInLine(Confrontation.LIGNE);
			if (Pattern.matches(OPER1.pattern(), ligne)) {
				Scanner sc0 = new Scanner(ligne);
				String inst = sc0.findInLine(INST);
				String op1 = sc0.findInLine(OP);
				String op2 = sc0.findInLine(OP);
				int a,b;
				sc0.close();
				
				Scanner sc1 = new Scanner(op1);
				String ma = sc1.findInLine(MODE);
				if (sc1.hasNextInt()) {a = sc1.nextInt();}
				else {a = etiquettes.get(sc1.findInLine(ETI)) - positionRelative;}
				sc1.close();
					
				Scanner sc2 = new Scanner(op2);
				String mb = sc2.findInLine(MODE);
				if (sc2.hasNextInt()) {b = sc2.nextInt();}
				else {
					String s = sc2.findInLine(ETI);
					if (s==null) {b = 0;}
					else {b = etiquettes.get(s) - positionRelative;}
				}
				sc2.close();
				prog[positionRelative] = new MotMemoire(inst, a, ma, b, mb);
				positionRelative++;
			}
			if (Pattern.matches(OPER2.pattern(), ligne)) {
				Scanner sc0 = new Scanner(ligne);
				String inst = sc0.findInLine(INST);
				String op1 = sc0.findInLine(OP);
				int a;
				sc0.close();
				
				Scanner sc1 = new Scanner(op1);
				String ma = sc1.findInLine(MODE);
				if (sc1.hasNextInt()) {a = sc1.nextInt();}
				else {a = etiquettes.get(sc1.findInLine(ETI)) - positionRelative;}
				sc1.close();
				
				int b = 0;
				String mb = "#";
				prog[positionRelative] = new MotMemoire(inst, a, ma, b, mb);
				positionRelative++;
			}
			if (sc.hasNext()) {sc.nextLine();}
    	}
    	sc.close();
    	
    	for (int i=positionRelative; i<VirtualMachine.MAXPROGLENGTH; i++) {
    		prog[i] = new MotMemoire("DAT", 0, "#", 0, "#");
    	}
    }
	
   // Faire la traduction
	public void parse(String filename) throws FileNotFoundException, ProgramLengthException, InstructionException, ModeException{
		File f = new File(filename);
		this.setLabel(f);
		this.setProgram(f);
	}
	
	public HashMap<String, Integer> getEtiquettes() {
		return etiquettes;
	}
	
	public MotMemoire[] getProg() {
		return prog;
	}
	
   // Remettre le Reader à zéro
	public void clear() {
		etiquettes = new HashMap<String, Integer>();
		prog = new MotMemoire[VirtualMachine.MAXPROGLENGTH];
	}
}
